﻿using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using JESAI.Core.Aspects;
using JESAI.Core.Threading.Locking;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace JESAI.Caching.MemoryCache
{
    public class MemoryCacheClient : CacheManager
    {
        private IMemoryCache _client;
        protected readonly SemaphoreSlim SemaphoreSlim = new SemaphoreSlim(1, 1);
        private readonly ILogger<MemoryCacheClient> _logger;
        //private ILogger logger = ServiceLocator.Instance.GetServices<ILogger<MemoryCacheClient>>().FirstOrDefault();
        public MemoryCacheClient(ILogger<MemoryCacheClient> logger)
        {
            _client = new Microsoft.Extensions.Caching.Memory.MemoryCache(new MemoryCacheOptions());
            _logger= logger;
        }
        public override bool Exits(string key)
        {
            return _client.TryGetValue(key, out var _);
        }
        public override T Get<T>(string key)
        {
            return _client.Get<T>(key);
        }
        public override bool Set<T>(string key, T item)
        {
            return _client.Set(key, item) is not null;
        }

        public override bool Set<T>(string key, T item, TimeSpan time)
        {
            return _client.Set(key, item, time) is not null;
        }

        public override long Del(string key)
        {
            _client.Remove(key);
            return 1;
        }

        public override TValue GetOrAdd<TValue>(string key, Func<string, TValue> factory)
        {
            if (TryGetValue(key, out TValue value))
            {
                return value;
            }

            using (SemaphoreSlim.Lock())
            {
                if (TryGetValue(key, out value))
                {
                    return value;
                }

                var generatedValue = factory(key);
                if (!IsDefaultValue(generatedValue))
                {
                    try
                    {
                        Set(key, generatedValue);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogException(ex);
                    }
                }
                return generatedValue;
            }
        }

        public override TValue GetOrAdd<TValue>(string key, Func<string, TValue> factory, TimeSpan time)
        {
            if (TryGetValue(key, out TValue value))
            {
                return value;
            }

            using (SemaphoreSlim.Lock())
            {
                if (TryGetValue(key, out value))
                {
                    return value;
                }

                var generatedValue = factory(key);
                if (!IsDefaultValue(generatedValue))
                {
                    try
                    {
                        Set(key, generatedValue, time);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogException(ex);
                    }
                }
                return generatedValue;
            }
        }
        protected bool IsDefaultValue<TValue>(TValue value)
        {
            return EqualityComparer<TValue>.Default.Equals(value, default);
        }
        public override bool TryGetValue<TValue>(string key, out TValue value)
        {
            return _client.TryGetValue(key, out value);
        }
    }
}
